import { reactive, VNode } from 'vue';
import { BaseType, ComponentType, Data, DictProps, EnumProps, http, httpConfig, loginConfig, PageIn } from '../index';


export interface AppConfig {
  app: {
    alias: string,
    appKeyHeaderName: string,
    initCfg: boolean,
    key: string,
    keys: Record<string, string>,
    listCfgsByAppKeys: (...appKeys: string[]) => Promise<Data[]>,
    pushHeaderName: string,
    requestIdHeaderName: string,
    title: string,
    traceIdHeaderName: string,
    version: number,
  }
  button: {
    resetTime: number
  },
  component: {
    Spin?: VNode
  },
  data: {
    date: string
    key: string
  },
  dict: {
    cache: boolean,
    valueKey: 'id' | 'value',
    listDictsByClass: (clazz: string, params?: any) => Promise<DictProps[]>
  },
  enum: {
    cache: boolean,
    listEnumsByClass: (clazz: string, appKey?: string) => Promise<EnumProps[]>,
    valueKey: 'key' | 'value'
  }
  env: string
  modal: {
    defaultWidthOrHeight: number
    lock: boolean,
    modalPicker: ComponentType,
    widthOrHeight: {
      bottom: BaseType[],
      center: BaseType[],
      left: BaseType[],
      right: BaseType[],
      top: BaseType[],
    }
  },
  number: {
    currencyPrecision: number
    currencyUnitValue: number
    decimalPrecision: number
    decimalUnitValue: number
    numberPrecision: number
  },
  page: {
    defaultPageSize: number
    onSort: (input: PageIn, field: string, direction: string) => void,
    pageNo: string,
    pageSize: string,
    rows: string,
    total: string
  },
  security: {
    encrypt: boolean,
    secret: string
  }
}

const appCfg = window.dmyConfig?.app ?? {}
export const appConfig: AppConfig = {
  app: {
    key: appCfg.app?.key ?? '',
    keys: appCfg.app?.keys ?? {},
    alias: appCfg.app?.alias ?? '',
    title: appCfg.app?.title ?? '',
    version: appCfg.app?.version ?? 100,
    appKeyHeaderName: appCfg.app?.appKeyHeaderName ?? 'x-dmy-app-key',
    pushHeaderName: appCfg.app?.pushHeaderName ?? 'x-dmy-push',
    requestIdHeaderName: appCfg.app?.requestIdHeaderName ?? 'x-dmy-request-id',
    traceIdHeaderName: appCfg.app?.traceIdHeader ?? 'x-dmy-trace-id',
    initCfg: false,
    listCfgsByAppKeys: (...appKeys: string[]) => {
      return http.post<Data[]>(`/api/sys/Cfg/listFrontendByAppKeys`, appKeys, {
        ignoreError: true,
        cache: { key: `cfg` },
      });
    },
  },
  button: {
    resetTime: 300,
  },
  component: {
    Spin: undefined,
  },
  data: {
    date: appCfg.data?.date ?? 'createdAt',
    key: appCfg.data?.key ?? 'id',
  },
  dict: {
    cache: appCfg.dict?.cache ?? true,
    valueKey: appCfg.dict?.valueKey ?? 'id',
    listDictsByClass(clazz: string, params: any): Promise<any[]> {
      return http.get<any[]>(`/api/sys/dict/listByClass/${clazz}`, params, {
        ignoreError: true,
        cache: { key: `dict-${clazz}` },
      })
    },
  },
  enum: {
    cache: appCfg.enum?.cache ?? true,
    valueKey: appCfg.enum?.valueKey ?? 'key',
    listEnumsByClass(clazz: string, appKey?: string): Promise<EnumProps[]> {
      return http.get<EnumProps[]>(`/api/enum/listByClass/${clazz}`, undefined, {
        appKey,
        ignoreError: true,
        cache: { key: `enum-${clazz}` },
      })
    },
  },
  env: appCfg.env || 'dev',
  modal: {
    defaultWidthOrHeight: 3,
    lock: false,
    modalPicker: '',
    widthOrHeight: {
      bottom: ['96%', '200px', '300px', '400px', '500px', '800px'],
      center: ['96%', '300px', '500px', '800px', '1100px', '1400px'],
      left: ['96%', '300px', '500px', '800px', '1100px', '1400px'],
      right: ['96%', '300px', '500px', '800px', '1100px', '1400px'],
      top: ['96%', '200px', '300px', '400px', '500px', '800px'],
    },
  },
  number: {
    currencyPrecision: appCfg.number?.currencyPrecision ?? 2,
    currencyUnitValue: appCfg.number?.currencyUnitValue ?? 100,
    decimalPrecision: appCfg.number?.decimalPrecision ?? 2,
    decimalUnitValue: appCfg.number?.decimalUnitValue ?? 100,
    numberPrecision: appCfg.number?.numberPrecision ?? 2,
  },
  page: {
    defaultPageSize: appCfg.page?.defaultPageSize ?? 10,
    onSort: (input: PageIn, field: string, direction: string): void => {
      if (direction === 'ascend') {
        direction = 'asc'
      }
      if (direction === 'descend') {
        direction = 'desc'
      }
      input.sorts = [field, direction]
    },
    pageNo: appCfg.page?.pageNo ?? 'pageNo',
    pageSize: appCfg.page?.pageSize ?? 'pageSize',
    rows: appCfg.page?.rows ?? 'rows',
    total: appCfg.page?.total ?? 'total',
  },
  security: {
    encrypt: appCfg.security?.encrypt ?? false,
    secret: appCfg.security?.secret ?? '',
  },
}

export const cfg: Data = reactive({
  user: {},
  tenant: {},
  app: {},
  token: {},
  login: {},
})

export async function listCfgsByClass(...appKeys: string[]) {
  const arr = await appConfig.app.listCfgsByAppKeys(...appKeys)
  if (!arr?.length) {
    return
  }
  for (const row of arr) {
    const { group, key, value } = row
    if (!cfg[group]) {
      cfg[group] = {}
    }
    if (value === 'true') {
      cfg[group][key] = true
    } else if (value === 'false') {
      cfg[group][key] = false;
    } else if (!isNaN(value)) {
      cfg[group][key] = Number(value);
    } else {
      cfg[group][key] = value
    }
  }

  cfg.token.tokenIdField && (loginConfig.tokenIdField = cfg.token.tokenIdField)
  cfg.token.tokenIdName && (loginConfig.tokenIdName = cfg.token.tokenIdName)
  cfg.token.tokenName && (loginConfig.tokenName = cfg.token.tokenName)
  cfg.token.refreshTokenName && (loginConfig.refreshTokenName = cfg.token.refreshTokenName)
  cfg.token.idTokenName && (loginConfig.idTokenName = cfg.token.idTokenName)
  cfg.token.tokenExpOffset && (loginConfig.tokenExpOffset = cfg.token.tokenExpOffset)
  cfg.token.withCredentials && (httpConfig.axios.withCredentials = cfg.token.withCredentials)
}

export async function initCfg() {
  const appKeys = Object.keys(appConfig.app.keys);
  await listCfgsByClass(...appKeys)
}
